package com.meilai.project.controller.web.businessFlow.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.meilai.project.constant.*;
import com.meilai.project.controller.web.businessFlow.dto.BFCustomerSearchParams;
import com.meilai.project.controller.web.businessFlow.entity.VBusiness;
import com.meilai.project.controller.web.businessFlow.mapper.VBusinessMapper;
import com.meilai.project.controller.web.businessFlow.vo.BFBillSaleVO;
import com.meilai.project.controller.web.businessFlow.vo.BFContractVO;
import com.meilai.project.controller.web.businessFlow.vo.BFCustomerVO;
import com.meilai.project.controller.web.businessFlow.vo.BFWorkOrderVO;
import com.meilai.project.entity.business.customer.CustomerInfo;
import com.meilai.project.entity.business.sale.BillSaleGroupRelation;
import com.meilai.project.entity.finance.invoice.InvoiceApply;
import com.meilai.project.entity.finance.invoice.InvoiceApplyAttachment;
import com.meilai.project.entity.finance.paymentReceived.AccountReceived;
import com.meilai.project.mapper.business.customer.CustomerInfoMapper;
import com.meilai.project.service.business.sale.BillSaleGroupRelationService;
import com.meilai.project.service.finance.invoice.InvoiceApplyAttachmentService;
import com.meilai.project.service.finance.invoice.InvoiceApplyService;
import com.meilai.project.service.finance.paymentReceived.AccountReceivedService;
import com.meilai.project.util.ThreadLocalUserUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 张驰
 * @description
 * @date 2022-09-14 16:37
 */
@Service
public class BusinessFlowServiceImpl implements BusinessFlowService {

    @Autowired
    private CustomerInfoMapper customerInfoMapper;
    @Autowired
    private VBusinessMapper vBusinessMapper;

    @Autowired
    private BillSaleGroupRelationService billSaleGroupRelationService;

    @Autowired
    private AccountReceivedService accountReceivedService;

    @Autowired
    private InvoiceApplyService invoiceApplyService;

    @Autowired
    private InvoiceApplyAttachmentService invoiceApplyAttachmentService;

    @Override
    public Page<BFCustomerVO> selectPageList(BFCustomerSearchParams params) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy.MM.dd");

        Page<BFCustomerVO> page = params.createPage(BFCustomerVO.class);
        Page<CustomerInfo> ciPage = params.createPage(CustomerInfo.class);
        List<Long> userIds = new ArrayList<>();
        if (Boolean.TRUE.equals(params.getIsCurrentUserMaintain())) userIds.add(ThreadLocalUserUtil.get().getId());
//        List<CustomerInfo> civs = customerInfoMapper.pageForBF(ciPage, params.getName(), userIds);
        /**
         * 数据只返回customerIds
         * 说明：
         * 1、排序逻辑：按完成百分比正序，完成百分比一样按客户id正序，后后面显示还没开始的
         * 2、参考主要视图：v_business、v_business_amount_all、v_business_amount_exe
         */
        List<Long> customerIds = customerInfoMapper.pageIdsForBF(ciPage, params.getName(), params.getContractBeginDate(), params.getContractEndDate(), params.getExecutionStatus(), userIds);

        BeanUtils.copyProperties(ciPage, page);
        page.setRecords(new ArrayList<>());
        List<Long> bill_sale_ids = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(customerIds)) {
            List<BFCustomerVO> list = new ArrayList<>();
//            List<Long> customerIds = civs.stream().map(CustomerInfo::getId).collect(Collectors.toList());
            List<VBusiness> vbs = vBusinessMapper.selectList(Wrappers.<VBusiness>lambdaQuery().in(VBusiness::getCustomer_id, customerIds));
            if (CollectionUtils.isNotEmpty(vbs)) {
                Map<Long, Map<Long, Map<Long, List<VBusiness>>>> vbsMap = vbs.stream()
                        .peek(d -> {
                            if (d.getContract_id() == null) d.setContract_id(0L);
                            if (d.getBill_sale_id() == null) d.setBill_sale_id(0L);
                        })
                        .collect(Collectors.groupingBy(VBusiness::getCustomer_id,
                                Collectors.groupingBy(VBusiness::getContract_id,
                                        Collectors.groupingBy(VBusiness::getBill_sale_id))));
                if (vbsMap != null && vbsMap.size() > 0) {
                    for (Map.Entry<Long, Map<Long, Map<Long, List<VBusiness>>>> customerEntry : vbsMap.entrySet()) {
                        BFCustomerVO cu = null;
                        for (Map.Entry<Long, Map<Long, List<VBusiness>>> contractEntry : customerEntry.getValue().entrySet()) {
                            BFContractVO co = null;
                            for (Map.Entry<Long, List<VBusiness>> billSaleEntry : contractEntry.getValue().entrySet()) {
                                BFBillSaleVO bs = null;
                                VBusiness firstOne = billSaleEntry.getValue().get(0);
                                if (cu == null) {
                                    cu = new BFCustomerVO();
                                    BeanUtils.copyProperties(firstOne, cu);
                                    cu.setId(firstOne.getCustomer_id());
                                }
                                if (co == null && !firstOne.getContract_id().equals(0L)) {
                                    co = new BFContractVO();
                                    BeanUtils.copyProperties(firstOne, co);
                                    co.setId(firstOne.getContract_id());
                                }
                                if (!firstOne.getBill_sale_id().equals(0L)) {
                                    bs = new BFBillSaleVO();
                                    BeanUtils.copyProperties(firstOne, bs);
                                    bs.setId(firstOne.getBill_sale_id());
                                }

                                if (bs != null) {
                                    bs.setWork_order_list(billSaleEntry.getValue().stream().filter(d -> d.getWork_order_id() != null)
                                            .map(d -> {
                                                BFWorkOrderVO wo = new BFWorkOrderVO();
                                                BeanUtils.copyProperties(d, wo);
                                                wo.setId(d.getWork_order_id());
                                                return wo;
                                            }).collect(Collectors.toList()));
                                    if (co != null) co.getBill_sale_list().add(bs);
                                }
                            }
                            if (co != null) cu.getContract_list().add(co);
                        }
                        list.add(cu);
                    }
                }
                if (CollectionUtils.isNotEmpty(list)) {
                    for (BFCustomerVO customerVO : list) {
                        BossUserEnum bossEnum = BossUserEnum.getEnumById(customerVO.getCustomer_charge_id());
                        customerVO.setCustomer_type_name(bossEnum == null ? BFCustomerTypeEnum.PERSONAL.getName() : BFCustomerTypeEnum.COMPANY.getName());

                        for (BFContractVO contractVO : customerVO.getContract_list()) {
                            customerVO.setCustomer_total(customerVO.getCustomer_total().add(contractVO.getContract_discounted_price()));

                            BFContractTypeEnum contractTypeEnum = contractVO.getContract_parent_id() == null ? BFContractTypeEnum.ORIGIN : BFContractTypeEnum.SUPPLY;
                            contractVO.setContract_type(contractTypeEnum.getId());
                            contractVO.setContract_type_name(contractTypeEnum.getName());

                            contractVO.setContract_status_name(Objects.requireNonNull(BFModeTypeEnum.getEnumById(contractVO.getContract_mode())).getName());

                            if (contractVO.getContract_flow_status().equals(FlowStatusEnum.SAVE.getId()))
                                contractVO.setContract_flow_status_name("已保存");
                            if (contractVO.getContract_flow_status().equals(FlowStatusEnum.PASSED.getId()))
                                contractVO.setContract_flow_status_name("已通过");
                            if (contractVO.getContract_flow_status().equals(FlowStatusEnum.RETURN_BACK.getId()))
                                contractVO.setContract_flow_status_name("被退回");

                            if (contractVO.getContract_begin_date() != null && contractVO.getContract_end_date() != null)
                                contractVO.setContract_date(dtf.format(contractVO.getContract_begin_date()) + " - " + dtf.format(contractVO.getContract_end_date()));

                            for (BFBillSaleVO billSaleVO : contractVO.getBill_sale_list()) {
                                BigDecimal exeAmount = Optional.ofNullable(billSaleVO.getBill_sale_execute_amount()).orElse(BigDecimal.ZERO);
                                billSaleVO.setBill_sale_execute_amount(exeAmount);
                                if (billSaleVO.getBill_sale_flow_status().equals(FlowStatusEnum.PASSED.getId())
                                        && billSaleVO.getBill_sale_mode().equals(BFModeTypeEnum.NORMAL.getId())) {
                                    contractVO.setContract_finished(contractVO.getContract_finished().add(exeAmount));
                                    customerVO.setCustomer_finished(customerVO.getCustomer_finished().add(exeAmount));
                                }
                                bill_sale_ids.add(billSaleVO.getId());
                                billSaleVO.setBill_sale_type_name(Objects.requireNonNull(BFChangeTypeEnum.getEnumById(billSaleVO.getBill_sale_type())).getName());

                                billSaleVO.setBill_sale_status_name(Objects.requireNonNull(BFModeTypeEnum.getEnumById(billSaleVO.getBill_sale_mode())).getName());

                                if (billSaleVO.getBill_sale_flow_status().equals(FlowStatusEnum.SAVE.getId()))
                                    billSaleVO.setBill_sale_flow_status_name("已保存");
                                if (billSaleVO.getBill_sale_flow_status().equals(FlowStatusEnum.PASSED.getId()))
                                    billSaleVO.setBill_sale_flow_status_name("已通过");
                                if (billSaleVO.getBill_sale_flow_status().equals(FlowStatusEnum.RETURN_BACK.getId()))
                                    billSaleVO.setBill_sale_flow_status_name("被退回");

                                if (billSaleVO.getStart_at() != null && billSaleVO.getEnd_at() != null)
                                    billSaleVO.setBill_sale_date(dtf.format(billSaleVO.getStart_at()) + " - " + dtf.format(billSaleVO.getEnd_at()));

                                if (billSaleVO.getBill_market_id() != null) {
                                    billSaleVO.setBill_market_has(true);

                                    billSaleVO.setBill_market_type_name(Objects.requireNonNull(BFChangeTypeEnum.getEnumById(billSaleVO.getBill_market_type())).getName());

                                    if (billSaleVO.getBill_market_flow_status().equals(FlowStatusEnum.SAVE.getId()))
                                        billSaleVO.setBill_market_flow_status_name("已保存");
                                    if (billSaleVO.getBill_market_flow_status().equals(FlowStatusEnum.PASSED.getId()))
                                        billSaleVO.setBill_market_flow_status_name("已通过");
                                    if (billSaleVO.getBill_market_flow_status().equals(FlowStatusEnum.RETURN_BACK.getId()))
                                        billSaleVO.setBill_market_flow_status_name("被退回");
                                }

                                if (billSaleVO.getBill_ad_make_id() != null) {
                                    billSaleVO.setBill_ad_make_has(true);

                                    billSaleVO.setBill_ad_make_type_name(Objects.requireNonNull(AdMakeOutTypeEnum.getEnumById(billSaleVO.getBill_ad_make_type())).getName());

                                    if (billSaleVO.getBill_ad_make_flow_status().equals(FlowStatusEnum.SAVE.getId()))
                                        billSaleVO.setBill_ad_make_flow_status_name("已保存");
                                    if (billSaleVO.getBill_ad_make_flow_status().equals(FlowStatusEnum.PASSED.getId()))
                                        billSaleVO.setBill_ad_make_flow_status_name("已通过");
                                    if (billSaleVO.getBill_ad_make_flow_status().equals(FlowStatusEnum.RETURN_BACK.getId()))
                                        billSaleVO.setBill_ad_make_flow_status_name("被退回");
                                }

                                billSaleVO.setWork_order_distributed(!billSaleVO.getWork_order_list().isEmpty());

                                billSaleVO.setWork_order_distributed_count(billSaleVO.getWork_order_list().size());

                                boolean woFinished = true;
                                int woFinishedCount = 0;
                                for (BFWorkOrderVO workOrderVO : billSaleVO.getWork_order_list()) {
                                    boolean curFinished = (workOrderVO.getWork_order_exe_status().equals(WorkOrderExecuteStatusEnum.COMPLETE.getId())
                                            || workOrderVO.getWork_order_exe_status().equals(WorkOrderExecuteStatusEnum.CLOSE.getId()));
                                    woFinished = woFinished && curFinished;
                                    if (curFinished) woFinishedCount++;

                                    workOrderVO.setWork_order_type_name(InstallTypeEnum.getName(workOrderVO.getWork_order_type()));

                                    workOrderVO.setWork_order_status_name(Objects.requireNonNull(BFModeTypeEnum.getEnumById(workOrderVO.getWork_order_mode())).getName());

                                    workOrderVO.setWork_order_exe_status_name(Objects.requireNonNull(WorkOrderExecuteStatusEnum.getEnumById(workOrderVO.getWork_order_exe_status())).getName());
                                }
                                billSaleVO.setWork_order_distributed_finished(woFinished);
                                billSaleVO.setWork_order_distributed_finished_count(woFinishedCount);
                            }
                            contractVO.getBill_sale_list().sort((o1, o2) -> {
                                int c1 = o2.getStart_at().compareTo(o1.getStart_at());
                                int c2 = o2.getEnd_at().compareTo(o1.getEnd_at());
                                return c1 > 0 ? c1 : c2;
                            });
                        }
                        customerVO.getContract_list().sort((o1, o2) -> {
                            int c1 = o2.getContract_begin_date().compareTo(o1.getContract_begin_date());
                            int c2 = o2.getContract_end_date().compareTo(o1.getContract_end_date());
                            return c1 > 0 ? c1 : c2;
                        });
                    }
                    list.sort((o1, o2) -> {
                        if (o1.getCustomer_total().compareTo(BigDecimal.ZERO) == 0 && o2.getCustomer_total().compareTo(BigDecimal.ZERO) > 0) {
                            return 1;
                        } else if (o1.getCustomer_total().compareTo(BigDecimal.ZERO) == 0 && o2.getCustomer_total().compareTo(BigDecimal.ZERO) == 0) {
                            return 0;
                        } else if (o1.getCustomer_total().compareTo(BigDecimal.ZERO) > 0 && o2.getCustomer_total().compareTo(BigDecimal.ZERO) == 0) {
                            return -1;
                        } else {
                            BigDecimal o1FinishedPer = o1.getCustomer_finished().divide(o1.getCustomer_total(), RoundingMode.HALF_UP);
                            BigDecimal o2FinishedPer = o2.getCustomer_finished().divide(o2.getCustomer_total(), RoundingMode.HALF_UP);
                            return o1FinishedPer.compareTo(o2FinishedPer);
                        }
                    });
                }
                if (CollectionUtils.isEmpty(bill_sale_ids)) {
                    bill_sale_ids.add(-1L);
                }
                List<BillSaleGroupRelation> relationList = new ArrayList<>();
                if(CollectionUtils.isNotEmpty(bill_sale_ids)) relationList = billSaleGroupRelationService.list(Wrappers.<BillSaleGroupRelation>lambdaQuery().in(BillSaleGroupRelation::getBill_sale_id, bill_sale_ids));
                List<Long> group_ids = relationList.stream().map(BillSaleGroupRelation::getGroup_id).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(group_ids)) {
                    group_ids.add(-1L);
                }
                Map<Long, List<AccountReceived>> group_received_map = accountReceivedService.list(Wrappers.<AccountReceived>lambdaQuery().in(AccountReceived::getGroup_id, group_ids)).stream().collect(Collectors.groupingBy(AccountReceived::getGroup_id));
                List<InvoiceApply> invoiceApplyList = invoiceApplyService.list(Wrappers.<InvoiceApply>lambdaQuery().eq(InvoiceApply::getFlow_status, 4).in(InvoiceApply::getGroup_id, group_ids));
                List<Long> collect = invoiceApplyList.stream().map(InvoiceApply::getId).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(collect)) {
                    collect.add(-1L);
                }
                Map<Long, List<InvoiceApplyAttachment>> map = invoiceApplyAttachmentService.list(Wrappers.<InvoiceApplyAttachment>lambdaQuery().in(InvoiceApplyAttachment::getInvoice_apply_id, collect)).stream().collect(Collectors.groupingBy(InvoiceApplyAttachment::getInvoice_apply_id));
                Map<Long, InvoiceApply> group_apply_map = invoiceApplyList.stream().collect(Collectors.toMap(InvoiceApply::getGroup_id, Function.identity()));
                Map<Long, BillSaleGroupRelation> billSaleGroupRelationMap = relationList.stream().collect(Collectors.toMap(BillSaleGroupRelation::getBill_sale_id, Function.identity()));
                for (BFCustomerVO bfCustomerVO : list) {
                    if (CollectionUtils.isNotEmpty(bfCustomerVO.getContract_list())) {
                        for (BFContractVO bfContractVO : bfCustomerVO.getContract_list()) {
                            if (CollectionUtils.isNotEmpty(bfContractVO.getBill_sale_list())) {
                                for (BFBillSaleVO bfBillSaleVO : bfContractVO.getBill_sale_list()) {
                                    BillSaleGroupRelation billSaleGroupRelation = billSaleGroupRelationMap.get(bfBillSaleVO.getId());
                                    if (billSaleGroupRelation != null) {
                                        Long groupId = billSaleGroupRelation.getGroup_id();
                                        if (group_apply_map.containsKey(groupId)) {
                                            InvoiceApply invoiceApply = group_apply_map.get(groupId);
                                            bfBillSaleVO.setInvoice_make_out(true);
                                            bfBillSaleVO.setInvoice_apply_id(invoiceApply.getId());
                                            if (map.containsKey(invoiceApply.getId())) {
                                                bfBillSaleVO.setUpload_material(true);
                                            } else {
                                                bfBillSaleVO.setUpload_material(false);
                                            }
                                        } else {
                                            bfBillSaleVO.setInvoice_make_out(false);
                                            bfBillSaleVO.setInvoice_apply_id(-1L);
                                            bfBillSaleVO.setUpload_material(false);
                                        }
                                        if (group_received_map.containsKey(groupId)) {
                                            List<AccountReceived> receiveds = group_received_map.get(groupId);
                                            bfBillSaleVO.setPayment_receive(true);
                                            bfBillSaleVO.setAccount_received_ids(receiveds.stream().map(AccountReceived::getId).collect(Collectors.toList()));
                                        } else {
                                            bfBillSaleVO.setPayment_receive(false);
                                            bfBillSaleVO.setAccount_received_ids(new ArrayList<>());
                                        }
                                    } else {
                                        bfBillSaleVO.setInvoice_make_out(false);
                                        bfBillSaleVO.setPayment_receive(false);
                                        bfBillSaleVO.setUpload_material(false);
                                        bfBillSaleVO.setInvoice_apply_id(-1L);
                                        bfBillSaleVO.setAccount_received_ids(new ArrayList<>());
                                    }
                                }
                            }
                        }
                    }
                }
                page.setRecords(list);
            }
        }

        return page;
    }

}
